home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / cpdir.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  6KB  |  266 lines

  1. /* cpdir - copy directory           Author: Erik Baalbergen */
  2.  
  3. /* Use "cpdir [-v] src dst" to make a copy dst of directory src.
  4.    Cpdir should behave like the UNIX shell command
  5.   (cd src; tar cf - .) | (mkdir dst; cd dst; tar xf -)
  6.  
  7.    The -m "merge" flag enables you to copy into an existing directory.
  8.    The -s "similar" flag preserves the full mode, uid, gid and times.
  9.    The -v "verbose" flag enables you to see what's going on when running cpdir.
  10.  
  11.    Work yet to be done:
  12.  
  13.   - link checks, i.e. am I not overwriting a file/directory by itself?
  14.  
  15.   Please report bugs and suggestions to erikb@cs.vu.nl
  16. */
  17.  
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <fcntl.h>
  21. #include <stdio.h>
  22.  
  23. #define MKDIR1 "/bin/mkdir"
  24. #define MKDIR2 "/usr/bin/mkdir"
  25.  
  26. #define BUFSIZE 1024
  27. #define PLEN    256
  28. #define DIRSIZ    16
  29.  
  30. #define MAXLINKS 512
  31.  
  32. struct {
  33.   unsigned short ino;
  34.   unsigned short dev;
  35.   char *path;
  36. } links[MAXLINKS];
  37. int nlinks = 0;
  38.  
  39. char *prog;
  40. int vflag = 0;            /* verbose */
  41. int mflag = 0;            /* force */
  42. int sflag = 0;            /* similar */
  43. char *strcpy();
  44. char *malloc();
  45.  
  46. main(argc, argv)
  47. char *argv[];
  48. {
  49.   int rc = 0;
  50.   char *p, *s;
  51.   struct stat st;
  52.  
  53.   prog = *argv++;
  54.   if ((p = *argv) && *p == '-') {
  55.     argv++;
  56.     argc--;
  57.     while (*++p) {
  58.         switch (*p) {
  59.             case 'v':    vflag = 1;    break;
  60.             case 'm':    mflag = 1;    break;
  61.             case 's':    sflag = 1;    break;
  62.             default:
  63.             fatal("illegal flag %s", p);
  64.         }
  65.     }
  66.   }
  67.   if (argc != 3) fatal("Usage: cpdir [-msv] source destination");
  68.   s = *argv++;
  69.   if (stat(s, &st) < 0) fatal("can't get file status of %s", s);
  70.   if ((st.st_mode & S_IFMT) != S_IFDIR) fatal("%s is not a directory", s);
  71.   cpdir(&st, s, *argv);
  72.   exit(0);
  73. }
  74.  
  75. cpdir(sp, s, d)
  76. struct stat *sp;
  77. char *s, *d;
  78. {
  79.   char spath[PLEN], dpath[PLEN];
  80.   char ent[DIRSIZ + 1];
  81.   register char *send = spath, *dend = dpath;
  82.   int fd, n;
  83.   struct stat st;
  84.   static first = 1;
  85.   static dev_t dev;
  86.   static ino_t ino;
  87.  
  88.   if ((fd = open(s, O_RDONLY)) < 0) {
  89.     nonfatal("can't read directory %s", s);
  90.     return;
  91.   }
  92.   if (
  93.       mflag == 0
  94.       ||
  95.       stat(d, &st) != 0
  96.       ||
  97.       (st.st_mode & S_IFMT) != S_IFDIR
  98.     ) {
  99.     make_dir(d);
  100.     if (sflag) similar(sp, d);
  101.   }
  102.   if (first) {
  103.     stat(d, &st);
  104.     dev = st.st_dev;
  105.     ino = st.st_ino;
  106.     first = 0;
  107.   }
  108.   if (sp->st_dev == dev && sp->st_ino == ino) {
  109.     nonfatal("%s skipped to avoid an endless loop", s);
  110.     return;
  111.   }
  112.   while (*send++ = *s++) {
  113.   }
  114.   while (*dend++ = *d++) {
  115.   }
  116.   send[-1] = '/';
  117.   dend[-1] = '/';
  118.   ent[DIRSIZ] = '\0';
  119.   while ((n = read(fd, ent, DIRSIZ)) == DIRSIZ) {
  120.     if (!((ent[0] == '\0' && ent[1] == '\0') || (ent[2] == '.') &&
  121.           (ent[3] == '\0' || (ent[3] == '.' && ent[4] == '\0'))
  122.           )) {
  123.         strcpy(send, ent + 2);
  124.         strcpy(dend, ent + 2);
  125.         if (stat(spath, &st) < 0)
  126.             fatal("can't get file status of %s", spath);
  127.         if ((st.st_mode & S_IFMT) != S_IFDIR && st.st_nlink > 1)
  128.             if (cplink(st, spath, dpath) == 1) continue;
  129.         switch (st.st_mode & S_IFMT) {
  130.             case S_IFDIR:
  131.             cpdir(&st, spath, dpath);
  132.             break;
  133.             case S_IFREG:
  134.             cp(&st, spath, dpath);
  135.             break;
  136.             default:
  137.             cpspec(&st, spath, dpath);
  138.             break;
  139.         }
  140.     }
  141.   }
  142.   close(fd);
  143.   if (n) fatal("error in reading directory %s", spath);
  144. }
  145.  
  146. make_dir(s)
  147. char *s;
  148. {
  149.   int pid, status;
  150.  
  151.   if (vflag) printf("mkdir %s\n", s);
  152.   if ((pid = fork()) == 0) {
  153.     execl(MKDIR1, "mkdir", s, (char *) 0);
  154.     execl(MKDIR2, "mkdir", s, (char *) 0);
  155.     fatal("can't execute %s or %s", MKDIR1, MKDIR2);
  156.   }
  157.   if (pid == -1) fatal("can't fork", prog);
  158.   wait(&status);
  159.   if (status) fatal("can't create %s", s);
  160. }
  161.  
  162. cp(sp, s, d)
  163. struct stat *sp;
  164. char *s, *d;
  165. {
  166.   char buf[BUFSIZE];
  167.   int sfd, dfd, n;
  168.  
  169.   if (vflag) printf("cp %s %s\n", s, d);
  170.   if ((sfd = open(s, O_RDONLY)) < 0)
  171.     nonfatal("can't read %s", s);
  172.   else {
  173.     if ((dfd = creat(d, sp->st_mode & 0777)) < 0)
  174.         fatal("can't create %s", d);
  175.     while ((n = read(sfd, buf, BUFSIZE)) > 0)
  176.         if (write(dfd, buf, n) != n)
  177.             fatal("error in writing file %s", d);
  178.     close(sfd);
  179.     close(dfd);
  180.     if (n) fatal("error in reading file %s", s);
  181.     if (sflag) similar(sp, d);
  182.   }
  183. }
  184.  
  185. similar(sp, d)
  186. struct stat *sp;
  187. char *d;
  188. {
  189.   time_t timep[2];
  190.  
  191.   chmod(d, sp->st_mode);
  192.   chown(d, sp->st_uid, sp->st_gid);
  193.   timep[0] = sp->st_atime;
  194.   timep[1] = sp->st_mtime;
  195.   utime(d, timep);
  196. }
  197.  
  198. nonfatal(s, a)
  199. char *s, *a;
  200. {
  201.   fprintf(stderr, "%s: ", prog);
  202.   fprintf(stderr, s, a);
  203.   fprintf(stderr, "\n");
  204. }
  205.  
  206. fatal(s, a)
  207. char *s, *a;
  208. {
  209.   nonfatal(s, a);
  210.   exit(1);
  211. }
  212.  
  213. cpspec(sp, s, d)
  214. struct stat *sp;
  215. char *s, *d;
  216. {
  217.   if (vflag) {
  218.     printf("copy special file %s to %s.", s, d);
  219.     printf(" Major/minor = %d/%d.",
  220.            sp->st_rdev >> 8, sp->st_rdev & 0177);
  221.     printf(" Mode = %o.\n", sp->st_mode);
  222.   }
  223.   if (mknod(d, sp->st_mode, sp->st_rdev, 0) < 0) {
  224.     perror("mknod");
  225.     nonfatal("Cannot create special file %s.\n", d);
  226.   }
  227.   if (sflag) similar(sp, d);
  228. }
  229.  
  230. cplink(st, spath, dpath)
  231. struct stat st;
  232. char *spath, *dpath;
  233. {
  234.   /* Handle files that are links. Returns 0 if file must be copied.
  235.    * Returns 1 if file has been successfully linked. */
  236.   int i;
  237.   int linkent;
  238.  
  239.   linkent = -1;
  240.   for (i = 0; i < nlinks; i++) {
  241.     if (links[i].dev == st.st_dev
  242.         && links[i].ino == st.st_ino)
  243.         linkent = i;
  244.   }
  245.   if (linkent >= 0) {        /* It's already in the link table *//* we
  246.              * must have copied it earlier. So just link
  247.              * to the saved dest path.         Don't copy it
  248.              * twice. */
  249.     if (vflag) printf("ln %s %s\n", links[linkent].path, dpath);
  250.     if (link(links[linkent].path, dpath) < 0)
  251.         fatal("Could not link to %s\n", dpath);
  252.     return(1);        /* Don't try to copy it */
  253.   } else {            /* Make an entry in the link table */
  254.     if (nlinks >= MAXLINKS) fatal("Too many links at %s\n", dpath);
  255.     links[nlinks].dev = st.st_dev;
  256.     links[nlinks].ino = st.st_ino;
  257.     links[nlinks].path = malloc(strlen(dpath) + 1);
  258.     if (links[nlinks].path == NULL)
  259.         fatal("No more memory at %s\n", dpath);
  260.     strcpy(links[nlinks].path, dpath);
  261.     nlinks++;
  262.     /* Go ahead and copy it the first time */
  263.     return(0);
  264.   }
  265. }
  266.